/*
This file is part of buco.  
Copyright (c) 2012 Christopher Pawelzik <christopher@cpawelzik.com>

Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 
*/ 
package buco.core.api;

/*
 * Represents version ranges of packages and bundles according to OSGi R4 Core Spec, p. 29
 */
public class VersionRange {
	private Version min; 
	private Version max; 	
	
	private boolean includeMin; 
	private boolean includeMax;
	
	public VersionRange(Version min, Version max, boolean includeMin, boolean includeMax) {
		this.min = min; 
		this.max = max; 
		this.includeMin = includeMin;
		this.includeMax = includeMax; 		
	}
	
	/*
	 * Contructor for a single version (max = infinite)	
	 */
	public VersionRange(Version min) {
		this.min = min; 
		this.max = null; 
		this.includeMin = true; 
	}	
	
	public static VersionRange fromString(String range) {				
		char leftOp = range.charAt(0);
		char rightOp = range.charAt(range.length() - 1);
		
		// A range can also be a single version
		if(!isOperator(leftOp) && !isOperator(rightOp)) {
			return new VersionRange(Version.fromString(range)); 
		}
		
		// Remove operators
		range = range.substring(1, range.length()-1); 
		
		// Get Versions 
		String[] elements = range.split(","); 
		
		Version min = Version.fromString(elements[0].trim());
		Version max = Version.fromString(elements[1].trim());		
				
		return new VersionRange(min, max, leftOp == '[', rightOp == ']'); 		
	}
	
	/*
	 * Determines if the given Version fits into this VersionRange. 
	 */
	public boolean matchesVersion(Version version) {
		// No max Version, test if min <= x
		if(this.max == null) { 
			return this.min.isLessThanOrEqual(version); 					
		}
		// min <= x <= max
		if(this.includeMin && this.includeMax) {
			return this.min.isLessThanOrEqual(version) && version.isLessThanOrEqual(this.max); 
		}
		// min <= x < max
		if(this.includeMin && !this.includeMax) {
			return this.min.isLessThanOrEqual(version) && version.isLessThan(this.max);
		}
		// min < x <= max
		if(!this.includeMin && this.includeMax) {
			return this.min.isLessThan(version) && version.isLessThanOrEqual(this.max);
		}
		// min < x < max
		if(!this.includeMin && !this.includeMax) {
			return this.min.isLessThan(version) && version.isLessThan(this.max);
		}		
		return false; 
	}
	
	@Override
	public String toString() {
		if(max == null) {
			return min.toString(); 
		}
		
		StringBuffer sb = new StringBuffer();		
		sb.append(includeMin ? "[" : "(");
		sb.append(min.toString());
		sb.append(","); 
		sb.append(max.toString());
		sb.append(includeMax ? "]" : ")"); 
		return sb.toString(); 
	}
		
	private static boolean isOperator(char c) {
		return c == '[' || c == ']' || c == '(' || c == ')'; 
	}

	public Version getMinVersion() {
		return min;
	}

	public Version getMaxVersion() {
		return max;
	}

	public boolean includeMinVersion() {
		return includeMin;
	}

	public boolean includeMaxVersion() {
		return includeMax;
	}
}
